<?php

namespace App\V3\Api\Services;

use App\V3\Api\Models\LogInStorageModel;
use App\V3\Api\Models\LogOutStorageModel;
use App\V3\Api\Models\MaterielsTypeModel;
use App\V3\Api\Models\SerialNumberModel;
use App\V3\Api\Models\StorageBatchModel;
use App\V3\Api\Models\StorageManageModel;
use App\V3\Api\Models\StorageModel;
use App\V3\Api\Models\StorageShelfLocationModel;
use App\V3\Api\Models\StorageShelfModel;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;

class AllocateService
{
    static public function allocate($data)
    {
        $data['shelf_id'] = empty($data['shelf_id']) ? 0 : $data['shelf_id'];
        $data['location_id'] = empty($data['location_id']) ? 0 : $data['location_id'];

        //验证目标仓库和库位信息
        $storageInfo = StorageModel::where([
            'id' => $data['storage_id'],
            'delete_flag' => 0
        ])->first();

        if (empty($storageInfo)) {
            return ['code' => 1, 'msg' => '无效仓库：目标仓库不存在', 'data' => ''];
        }

        if ($data['is_use_shelf']) {
            if (empty($data['location_id'])) {
                return ['code' => 1, 'msg' => '请选择库位', 'data' => ''];
            }

            $checkLocation = StorageShelfLocationModel::where([
                'storage_id' => $data['storage_id'],
                'shelf_id' => $data['shelf_id'],
                'id' => $data['location_id'],
                'status' => 1
            ])
                ->first();

            if (empty($checkLocation)) {
                return ['code' => 1, 'msg' => '无效库位，或已被删除', 'data' => ''];
            }
        } else {//获取默认库位信息
            $shelfInfo = StorageShelfModel::where([
                'storage_id' => $data['storage_id'],
                'shelf_type' => 1
            ])->first();

            $data['shelf_id'] = $shelfInfo['id'];

            $locationInfo = StorageShelfLocationModel::where([
                'shelf_id' => $shelfInfo['id'],
                'location_type' => 1
            ])
                ->first();

            $data['location_id'] = $locationInfo['id'];
        }

        $allocateInfo = json_decode($data['allocate_info'], true);

        if (empty($allocateInfo)) {
            return ['code' => 1, 'msg' => '请选择需要调拨的商品信息', 'data' => ''];
        }

        DB::beginTransaction();

        try {
            $serialData = [];//被调拨的序列号
            $logData = [];
            $targetStorageManageData = [];
            $batchOutData = [];
            foreach ($allocateInfo as $value) {
                //目标库存信息
                $targetStorageManageInfo = self::getNewStorageManageInfo($value['id']);
                //商品原信息
                $materielTypeInfo = MaterielsTypeModel::select(
                    'a.*',
                    'b.class_name',
                    'b.class_no'
                )
                    ->from('materiel_type as a')
                    ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
                    ->where('a.id', $targetStorageManageInfo['type_id'])
                    ->first();

                if($targetStorageManageInfo['storage_id'] == $data['storage_id']) {
                    throw new Exception('禁止同库调拨');
                }

                if($value['allocate_num'] > $targetStorageManageInfo['virtual_storage_num']) {
                    throw new Exception('库存商品:'.$targetStorageManageInfo['materiel_name'].
                        '-'.$targetStorageManageInfo['type_name'].
                        '调拨数量X'.$value['allocate_num'].
                        ',可用库存数(X'.$targetStorageManageInfo['virtual_storage_num'].')不足,无法完成调拨');
                }

                if($value['allocate_num'] > $targetStorageManageInfo['in_storage_num']) {
                    throw new Exception('库存商品:'.$targetStorageManageInfo['materiel_name'].'-'.$targetStorageManageInfo['type_name'].
                        '调拨数量X'.$value['allocate_num'].
                        ',剩余库存数(X'.$targetStorageManageInfo['in_storage_num'].')不足,无法完成调拨');
                }

                $allocateInInfo = self::checkExist($data, $materielTypeInfo);//校验调入库存是否存在

                $targetStorageManageData[] = [
                    'id' => $targetStorageManageInfo['id'],
                    'virtual_storage_num' => $targetStorageManageInfo['virtual_storage_num'] - $value['allocate_num'],
                    'in_storage_num' => $targetStorageManageInfo['in_storage_num'] - $value['allocate_num'],
                ];

                $storageManageId = 0;
                $serialNoStr = '';
                $batchId = 0;

                if(empty($allocateInInfo)) {
                    $storageManageId = self::createNewStorageInfo($data, $materielTypeInfo, $storageInfo, $value['allocate_num']);
                }
                else {
                    $storageManageId = $allocateInInfo['id'];
                    StorageManageModel::where('id', $allocateInInfo['id'])
                        ->update([
                            'virtual_storage_num' => $allocateInInfo['virtual_storage_num'] + $value['allocate_num'],
                            'in_storage_num' => $allocateInInfo['in_storage_num'] + $value['allocate_num'],
                            'delete_flag' => 0
                        ]);
                }

                if($materielTypeInfo['is_use_serial']) {
                    if(count($value['serial_info']) < $value['allocate_num']) {
                        throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.$materielTypeInfo['type_name'].
                            '调拨所需序列号数量X'.$value['allocate_num'].
                            ',序列号尚缺X'.($value['allocate_num'] - count($value['serial_info'])).',无法完成调拨');
                    }

                    if(count($value['serial_info']) > $value['allocate_num']) {
                        throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.$materielTypeInfo['type_name'].
                            '调拨所需序列号数量X'.$value['allocate_num'].
                            ',序列号尚超出X'.(count($value['serial_info'] - $value['allocate_num'])).',无法完成调拨');
                    }

                    foreach($value['serial_info'] as $serialValue) {
                        $getSerialInfo = SerialNumberModel::where('id', $serialValue['serial_id'])->first();

                        if(!$getSerialInfo['status']) {
                            throw new Exception('序列号:'.$getSerialInfo['serial_no'].'已被占用，无法调拨');
                        }

                        $serialNoStr .= $getSerialInfo['serial_no'].',';
                        $serialData[] = [
                            'id' => $serialValue['serial_id'],
                            'storage_manage_id' => $storageManageId
                        ];
                    }
                }
                else {
                    if ($data['is_batch_out']) {//批次号逻辑废弃
                        if(empty($value['batch_info'])) {
                            throw new Exception('请选择要调拨的批次号');
                        }

                        $targetTotalBatchNum = 0;
                        foreach($value['batch_info'] as $batchValue) {
                            $targetTotalBatchNum += $batchValue['num'];

                            $batchInfo = StorageBatchModel::where('id', $batchValue['batch_id'])
                                ->first();

                            if (empty($batchInfo)) {
                                throw new Exception('批次号不存在');
                            }

                            //批次号对应库存信息
                            $batchStorageManageInfo = StorageManageModel::where('id', $batchInfo['storage_manage_id'])->first();

                            if($batchStorageManageInfo['in_storage_num'] < $batchInfo['batch_left_num']) {
                                if($batchValue['num'] > $batchInfo['batch_left_num']) {
                                    throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.$materielTypeInfo['type_name'].',批次号:'.$batchInfo['batch_no'].
                                        ',调拨所需批次数量X'.$value['allocate_num'].
                                        ',批次库存数量(X'.$batchStorageManageInfo['in_storage_num'].')不足,无法完成调拨');
                                }
                            }

                            if($batchStorageManageInfo['virtual_storage_num'] < $batchInfo['batch_left_num']) {
                                if($batchValue['num'] > $batchInfo['batch_left_num']) {
                                    throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.$materielTypeInfo['type_name'].',批次号:'.$batchInfo['batch_no'].
                                        ',调拨所需批次数量X'.$value['allocate_num'].
                                        ',批次可用库存数量(X'.$batchStorageManageInfo['in_storage_num'].')不足,无法完成调拨');
                                }
                            }

                            if($batchValue['num'] > $batchInfo['batch_left_num']) {
                                throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.$materielTypeInfo['type_name'].',批次号:'.$batchInfo['batch_no'].
                                    ',调拨所需批次数量X'.$value['allocate_num'].
                                    ',批次数量尚缺X'.($value['allocate_num'] - $targetTotalBatchNum).',无法完成调拨');
                            }

                            $batchOutData[] = [
                                'id' => $batchInfo['id'],
                                'batch_left_num' => $batchInfo['batch_left_num'] - $batchValue['num']
                            ];
                        }

                        if($value['allocate_num'] > $targetTotalBatchNum) {
                            throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.$materielTypeInfo['type_name'].
                                '调拨所需批次数量X'.$value['allocate_num'].
                                ',批次数量尚缺X'.($value['allocate_num'] - $targetTotalBatchNum).',无法完成调拨');
                        }

                        if($value['allocate_num'] < $targetTotalBatchNum) {
                            throw new Exception('商品:'.$materielTypeInfo['materiel_name'].'-'.$materielTypeInfo['type_name'].
                                '调拨所需批次数量X'.$value['allocate_num'].
                                ',批次数量尚缺X'.($targetTotalBatchNum - $value['allocate_num']).',无法完成调拨');
                        }
                    }
                }

                $batchNo = self::generatorBatchNo($data);
                $batchId = self::createdBatch($batchNo, $storageManageId, $materielTypeInfo, $data, $value['allocate_num']);

                $logInId = self::generatorAllocateInLog(
                    $data,
                    $storageManageId,
                    $targetStorageManageInfo,
                    $storageInfo,
                    $targetStorageManageInfo['in_storage_num'],
                    $value['allocate_num'],
                    $batchId,
                    $serialNoStr,
                );
                $logOutId = self::generatorAllocateOutLog(
                    $data,
                    $targetStorageManageInfo,
                    $storageInfo,
                    $storageManageId,
                    $materielTypeInfo,
                    $value['allocate_num'],
                    $serialNoStr,
                    $batchId,
                );

                LogInStorageModel::where('id', $logInId)
                    ->update([
                        'log_out_id' => $logOutId
                    ]);

                LogOutStorageModel::where('id', $logOutId)
                    ->update([
                        'log_in_id' => $logInId
                    ]);
            }

            if(!empty($serialData)) {
                batch()->update(new SerialNumberModel, $serialData, 'id');
            }

            if(!empty($targetStorageManageData)) {
                batch()->update(new StorageManageModel, $targetStorageManageData, '');
            }

            if(!empty($batchOutData)) {
                batch()->update(new StorageBatchModel, $batchOutData, '');
            }

            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        }
        catch(Exception $e) {
            DB::rollBack();
            Log::debug('调拨异常:'.var_export($e->getMessage(), true));
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }
    static public function allocate1($data)
    {
        $data['shelf_id'] = empty($data['shelf_id']) ? 0 : $data['shelf_id'];
        $data['location_id'] = empty($data['location_id']) ? 0 : $data['location_id'];

        //验证目标仓库和库位信息
        $storageInfo = StorageModel::where([
            'id' => $data['storage_id'],
            'delete_flag' => 0
        ])->first();

        if (empty($storageInfo)) {
            return ['code' => 1, 'msg' => '无效仓库：目标仓库不存在', 'data' => ''];
        }

        if ($data['is_use_shelf']) {
            if (empty($data['location_id'])) {
                return ['code' => 1, 'msg' => '请选择库位', 'data' => ''];
            }

            $checkLocation = StorageShelfLocationModel::where([
                'storage_id' => $data['storage_id'],
                'shelf_id' => $data['shelf_id'],
                'id' => $data['location_id'],
                'status' => 1
            ])
                ->first();

            if (empty($checkLocation)) {
                return ['code' => 1, 'msg' => '无效库位，或已被删除', 'data' => ''];
            }
        } else {//获取默认库位信息
            $shelfInfo = StorageShelfModel::where([
                'storage_id' => $data['storage_id'],
                'shelf_type' => 1
            ])->first();

            $data['shelf_id'] = $shelfInfo['id'];

            $locationInfo = StorageShelfLocationModel::where([
                'shelf_id' => $shelfInfo['id'],
                'location_type' => 1
            ])
                ->first();

            $data['location_id'] = $locationInfo['id'];
        }

        $allocateInfo = json_decode($data['allocate_info'], true);

        if (empty($allocateInfo)) {
            return ['code' => 1, 'msg' => '请选择需要调拨的商品信息', 'data' => ''];
        }

        DB::beginTransaction();

        try {
            foreach ($allocateInfo as $value) {
                $storageManageInfo = self::getStorageManageInfo($value['id']);

                $materielTypeInfo = MaterielsTypeModel::select(
                    'a.*',
                    'b.class_name',
                    'b.class_no'
                )
                    ->from('materiel_type as a')
                    ->leftJoin('materiel_class as b', 'b.id', '=', 'a.materiel_class_id')
                    ->where('a.id', $storageManageInfo['type_id'])
                    ->first();

                $allocateInInfo = self::checkExist($data, $materielTypeInfo);//校验目标库存是否存在

                if (empty($storageManageInfo)) {
                    throw new Exception('无效库存：目标库存信息不存在');
                }

                if ($materielTypeInfo['is_use_serial']) {
                    if (empty($value['serial_info'])) {
                        throw new Exception('请选择要调拨的序列号');
                    }

                    $serialNum = 0;
                    foreach ($value['serial_info'] as $serialValue) {
                        if($serialValue['num'] > 1) {
                            throw new Exception('序列号数量最小单位仅能为1');
                        }

                        $serialNum += $serialValue['num'];

                        $serialInfo = SerialNumberModel::where('id', $serialValue['serial_id'])->first();

                        if (empty($serialInfo) || $serialInfo['status'] == 0) {
                            throw new Exception('序列号不存在或已使用,请重新选择');
                        }

                        //序列号对应库存信息
                        $serialStorageManageInfo = StorageManageModel::where('id', $serialInfo['storage_manage_id'])->first();

                        if($serialStorageManageInfo['in_storage_num'] < 1) {
                            throw new Exception('序列号:'.$serialInfo['serial_no'].'对应的库存数量不足,无法完成调拨');
                        }

                        if($serialStorageManageInfo['storage_id'] == $data['storage_id']) {
//                        if($serialStorageManageInfo['location_id'] == $data['location_id']) {
                            throw new Exception('库存商品' . $materielTypeInfo['materiel_name'] . '-' . $materielTypeInfo['type_name'] . '禁止同库调拨');
                        }

//                        $serialStorageInfo = StorageModel::where('id', $serialStorageManageInfo['storage_id'])->first();

                        self::serialAllocate($allocateInInfo, $data, $storageInfo, $serialStorageManageInfo, $materielTypeInfo, $serialValue['num'], $serialInfo);
                    }

                    if ($value['allocate_num'] < $serialNum) {
                        throw new Exception('库存商品' . $materielTypeInfo['materiel_name'] . '-' . $materielTypeInfo['type_name'] . '序列号已选数量超出调拨数量');
                    }

                    if ($value['allocate_num'] > $serialNum) {
                        throw new Exception('库存商品' . $materielTypeInfo['materiel_name'] . '-' . $materielTypeInfo['type_name'] . '已选序列号数量小于调拨数量');
                    }
                } else {
                    if (!empty($data['is_batch_out'])) $data['is_batch_out'] = 0;
                    if ($data['is_batch_out']) {//批次号逻辑废弃
                        if (empty($value['batch_info'])) {
                            throw new Exception('请选择要调拨的批次号');
                        }

                        $batchNum = 0;
                        foreach ($value['batch_info'] as $batchValue) {
                            $batchNum += $batchValue['num'];

                            $batchInfo = StorageBatchModel::where('id', $batchValue['batch_id'])->first();

                            //批次号对应库存信息
                            $batchStorageManageInfo = StorageManageModel::where('id', $batchInfo['storage_manage_id'])->first();

                            if (empty($batchInfo)) {
                                throw new Exception('批次号不存在');
                            }

                            if ($batchValue['num'] > $batchInfo['batch_left_num']) {
                                throw new Exception('批次号:' . $batchInfo['batch_no'] . '剩余可用数量不足,无法调拨');
                            }

                            if($batchStorageManageInfo['in_storage_num'] < $batchValue['num']) {
                                throw new Exception('批次号:' . $batchInfo['batch_no'] . '对应的库存数量不足,无法调拨,当前剩余库存数量：'.$batchStorageManageInfo['in_storage_num']);
                            }

                            if($batchStorageManageInfo['storage_id'] == $data['storage_id']) {
                                throw new Exception('库存商品' . $materielTypeInfo['materiel_name'] . '-' . $materielTypeInfo['type_name'] . '禁止同库调拨');
                            }

//                            $batchStorageInfo = StorageModel::where('id', $batchStorageManageInfo['storage_id'])->first();

                            self::batchAllocate($allocateInInfo, $data, $storageInfo, $batchStorageManageInfo, $materielTypeInfo, $batchValue['num'], $batchInfo);
                        }

                        if ($value['allocate_num'] < $batchNum) {
                            throw new Exception('所选的批次数量超出实际调拨数量，无法完成调拨');
                        }

                        if ($value['allocate_num'] > $batchNum) {
                            throw new Exception('所选的批次数量少于实际调拨数量，无法完成调拨');
                        }
                    } else {
                        if ($storageManageInfo['in_storage_num'] == 0 || $storageManageInfo['in_storage_num'] < $value['allocate_num']) {
                            throw new Exception('库存商品' . $materielTypeInfo['materiel_name'] . '-' . $materielTypeInfo['type_name'] . '库存数不足,当前库存数量为：' . $storageManageInfo['in_storage_num']);
                        }

                        if($storageManageInfo['storage_id'] == $data['storage_id']) {
                            throw new Exception('库存商品' . $materielTypeInfo['materiel_name'] . '-' . $materielTypeInfo['type_name'] . '禁止同库调拨');
                        }

                        self::normalAllocate($allocateInInfo, $data, $storageInfo, $storageManageInfo, $materielTypeInfo, $value['allocate_num']);
                    }
                }
            }
            DB::commit();
            return ['code' => 0, 'msg' => 'success', 'data' => ''];
        } catch (Exception $e) {
            DB::rollBack();
            return ['code' => 1, 'msg' => $e->getMessage(), 'data' => ''];
        }
    }

    static private function serialAllocate($allocateInInfo, $data, $storageInfo, $storageManageInfo, $materielTypeInfo, $allocateNum, $serialInfo)
    {
        if(empty($allocateInInfo)) {
            $storageManageId = self::createNewStorageInfo($data, $materielTypeInfo, $storageInfo, $allocateNum);

            StorageManageModel::where('id', $storageManageInfo['id'])->update([
                'in_storage_num' => DB::raw('in_storage_num -'.$allocateNum),
                'virtual_storage_num' => DB::raw('virtual_storage_num -'.$allocateNum),
            ]);

            $currStorageNum = 0;
            $uselessAllocate = 0;
        }
        else {
            $storageManageId = $allocateInInfo['id'];

            if($serialInfo['storage_manage_id'] != $allocateInInfo['id']) {
                StorageManageModel::where('id', $allocateInInfo['id'])
                    ->update([
                        'in_storage_num' => DB::raw('in_storage_num +'.$allocateNum),
                        'virtual_storage_num' => DB::raw('virtual_storage_num +'.$allocateNum),
                        'delete_flag' => 0
                    ]);

                StorageManageModel::where('id', $storageManageInfo['id'])->update([
                    'in_storage_num' => DB::raw('in_storage_num -'.$allocateNum),
                    'virtual_storage_num' => DB::raw('virtual_storage_num -'.$allocateNum),
                ]);

                $currStorageNum = $allocateInInfo['in_storage_num'];
                $uselessAllocate = 0;
            }
            else {
                $uselessAllocate = 1;
            }
        }

        $batchNo = self::generatorBatchNo($data);
        $batchId = self::createdBatch($batchNo, $storageManageId, $materielTypeInfo, $data, $allocateNum);

        if(!$uselessAllocate) {
            SerialNumberModel::where('id', $serialInfo['id'])
                ->update([
                    'storage_manage_id' => $storageManageId
                ]);

            $logInId = self::generatorAllocateInLog($data, $storageManageId, $storageManageInfo, $storageInfo, $currStorageNum, $allocateNum, $batchId, $serialInfo['serial_no']);
            $logOutId = self::generatorAllocateOutLog($data, $storageManageInfo, $storageInfo, $storageManageId, $materielTypeInfo, $allocateNum, $serialInfo['serial_no'], $batchId);

            LogInStorageModel::where('id', $logInId)
                ->update([
                    'log_out_id' => $logOutId
                ]);

            LogOutStorageModel::where('id', $logOutId)
                ->update([
                    'log_in_id' => $logInId
                ]);
        }

        return true;
    }

    //批次号调拨
    static private function batchAllocate($allocateInInfo, $data, $storageInfo, $storageManageInfo, $materielTypeInfo, $allocateNum, $batchInfo)
    {
        if(empty($allocateInInfo)) {
            $storageManageId = self::createNewStorageInfo($data, $materielTypeInfo, $storageInfo, $allocateNum);
            $currStorageNum = 0;

            $batchId = StorageBatchModel::insertGetId([
                'batch_no' => $batchInfo['batch_no'],
                'storage_manage_id' => $storageManageId,
                'batch_num' => $allocateNum,
                'batch_left_num' => $allocateNum,
                'batch_cost' => $storageManageInfo['materiel_mean_cost'],
                'main_id' => $data['main_id'],
                'created_at' => time()
            ]);
        }
        else {
            StorageManageModel::where('id', $allocateInInfo['id'])
                ->update([
                    'in_storage_num' => DB::raw('in_storage_num +'.$allocateNum),
                    'virtual_storage_num' => DB::raw('virtual_storage_num +'.$allocateNum),
                    'delete_flag' => 0
                ]);

            $storageManageId = $allocateInInfo['id'];
            $currStorageNum = $allocateInInfo['in_storage_num'];

            $checkBatchInfo = StorageBatchModel::where([
                'storage_manage_id' => $allocateInInfo['id'],
                'id' => $batchInfo['id'],
                'delete_flag' => 0
            ])->first();

            if(empty($checkBatchInfo)) {
                $batchId = StorageBatchModel::insertGetId([
                    'batch_no' => $batchInfo['batch_no'],
                    'storage_manage_id' => $storageManageId,
                    'batch_num' => $allocateNum,
                    'batch_left_num' => $allocateNum,
                    'batch_cost' => $allocateInInfo['materiel_mean_cost'],
                    'main_id' => $data['main_id'],
                    'created_at' => time()
                ]);
            }
            else {
                StorageBatchModel::where('id', $checkBatchInfo['id'])
                    ->update([
                        'batch_num' => DB::raw('batch_num +'.$allocateNum),
                        'batch_left_num' => DB::raw('batch_left_num +'.$allocateNum),
                        'delete_flag' => 0
                    ]);

                $batchId = $checkBatchInfo['id'];
            }
        }

        StorageManageModel::where('id', $storageManageInfo['id'])->update([
            'in_storage_num' => DB::raw('in_storage_num -'.$allocateNum),
            'virtual_storage_num' => DB::raw('virtual_storage_num -'.$allocateNum),
        ]);

        StorageBatchModel::where('id', $batchInfo['id'])
            ->update([
                'batch_num' => DB::raw('batch_num -'.$allocateNum),
                'batch_left_num' => DB::raw('batch_left_num -'.$allocateNum),
                'delete_flag' => 0
            ]);

        $logInId = self::generatorAllocateInLog($data, $storageManageId, $storageManageInfo, $storageInfo, $currStorageNum, $allocateNum, $batchId, '', $batchInfo['id']);
        $logOutId = self::generatorAllocateOutLog($data, $storageManageInfo, $storageInfo, $storageManageId, $materielTypeInfo, $allocateNum, '', $batchId, $batchInfo['id']);

        LogInStorageModel::where('id', $logInId)
            ->update([
                'log_out_id' => $logOutId
            ]);

        LogOutStorageModel::where('id', $logOutId)
            ->update([
                'log_in_id' => $logInId
            ]);

        return true;
    }

    /**
     *
     * @param $allocateInInfo 目标库存信息
     * @param $data 表单获取的数据
     * @param $storageInfo 调出仓库信息
     * @param $storageManageInfo 调出库存信息
     * @param $materielTypeInfo 调出商品信息
     * 2022/9/27 15:19
     * Author: Sun Wu
     * @return bool
     */
    static private function normalAllocate($allocateInInfo, $data, $storageInfo, $storageManageInfo, $materielTypeInfo, $allocateNum)
    {
        if(empty($allocateInInfo)) {
            $storageManageId = self::createNewStorageInfo($data, $materielTypeInfo, $storageInfo, $allocateNum);
            $currStorageNum = 0;
        }
        else {
            StorageManageModel::where('id', $allocateInInfo['id'])
                ->update([
                    'in_storage_num' => DB::raw('in_storage_num +'.$allocateNum),
                    'virtual_storage_num' => DB::raw('virtual_storage_num +'.$allocateNum),
                    'delete_flag' => 0
                ]);

            $storageManageId = $allocateInInfo['id'];
            $currStorageNum = $allocateInInfo['in_storage_num'];
        }

        StorageManageModel::where('id', $storageManageInfo['id'])->update([
            'in_storage_num' => DB::raw('in_storage_num -'.$allocateNum),
            'virtual_storage_num' => DB::raw('virtual_storage_num -'.$allocateNum),
        ]);

        $batchNo = self::generatorBatchNo($data);
        $batchId = self::createdBatch($batchNo, $storageManageId, $materielTypeInfo, $data, $allocateNum);

        $logInId = self::generatorAllocateInLog($data, $storageManageId, $storageManageInfo, $storageInfo, $currStorageNum, $allocateNum, $batchId);
        $logOutId = self::generatorAllocateOutLog($data, $storageManageInfo, $storageInfo, $storageManageId, $materielTypeInfo, $allocateNum);

        LogInStorageModel::where('id', $logInId)
            ->update([
                'log_out_id' => $logOutId
            ]);

        LogOutStorageModel::where('id', $logOutId)
            ->update([
                'log_in_id' => $logInId
            ]);

        return true;
    }

    static public function generatorAllocateOutLog($data, $storageManageInfo, $storageInfo, $nextStorageManageId, $materielTypeInfo, $allocateNum, $serialInfo = '', $batchId = '', $beforBatchId = 0)
    {
        return LogOutStorageModel::insertGetId([
            'type' => 1,
            'storage_batch_id' => $batchId,
            'allocate_no' => $data['allocate_no'],
            'before_allocate_batch_id' => $beforBatchId,
            'storage_id' => $storageManageInfo['storage_id'],
            'storage_name' => $storageManageInfo['storage_name'],
            'storage_address' => $storageManageInfo['storage_address'],
            'next_storage_id' => $storageInfo['id'],
            'next_storage_name' => $storageInfo['storage_name'],
            'next_storage_address' => $storageInfo['storage_address'],
            'curr_storage_manage_id' => $storageManageInfo['id'],
            'next_storage_manage_id' => $nextStorageManageId,
            'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
            'materiel_class_name' => $materielTypeInfo['class_name'],
            'materiel_class_no' => $materielTypeInfo['class_no'],
            'materiel_type_id' => $materielTypeInfo['id'],
            'materiel_name' => $materielTypeInfo['materiel_name'],
            'type_name' => $materielTypeInfo['type_name'],
            'materiel_no' => $materielTypeInfo['materiel_no'],
            'operate_num' => $allocateNum,
            'last_storage_num' => $storageManageInfo['in_storage_num'],
            'next_storage_num' => $storageManageInfo['in_storage_num'] - $allocateNum,
            'serial_number' => $serialInfo,
            'sell_price' => $materielTypeInfo['selling_price'],
            'materiel_mean_cost' => $materielTypeInfo['cost'],
            'user_id' => $data['user_id'],
            'main_id' => $data['main_id'],
            'remark' => empty($data['remark'])?'':$data['remark'],
            'out_storage_time' => time(),
            'fact_out_time' => time(),
            'created_at' => time(),
            'shelf_id' => $data['shelf_id'],
            'location_id' => $data['location_id'],
        ]);
    }

    static public function generatorAllocateInLog($data, $storageManageId, $storageManageInfo, $storageInfo, $currStorageNum, $allocateNum, $batchId, $serialInfo = '', $beforeBatchId = '')
    {
        return LogInStorageModel::insertGetId([
            'type' => 1,
            'storage_id' => $storageInfo['id'],
            'storage_name' => $storageInfo['storage_name'],
            'storage_address' => $storageInfo['storage_address'],
            'last_storage_manage_id' => $storageManageInfo['id'],
            'curr_storage_manage_id' => $storageManageId,
            'last_storage_id' => $storageManageInfo['storage_id'],
            'last_storage_name' => $storageManageInfo['storage_name'],
            'last_storage_address' => $storageManageInfo['storage_address'],
            'materiel_class_id' => $storageManageInfo['materiel_class_id'],
            'materiel_class_name' => $storageManageInfo['class_name'],
            'materiel_class_no' => $storageManageInfo['class_no'],
            'materiel_type_id' => $storageManageInfo['type_id'],
            'materiel_name' => $storageManageInfo['materiel_name'],
            'type_name' => $storageManageInfo['type_name'],
            'materiel_no' => $storageManageInfo['materiel_no'],
            'operate_num' => $allocateNum,
            'allocate_no' => $data['allocate_no'],
            'last_storage_num' => $currStorageNum,
            'next_storage_num' => $currStorageNum + $allocateNum,
            'materiel_mean_cost' => $storageManageInfo['cost'],
            'serial_number' => $serialInfo,
            'remark' => empty($data['remark'])?'':$data['remark'],
            'batch_id' => $batchId,
            'before_allocate_batch_id' => $beforeBatchId,
            'all_id_type' => 0,
            'all_id' => 0,
            'user_id' => $data['user_id'],
            'main_id' => $data['main_id'],
            'in_storage_time' => time(),
            'created_at' => time(),
            'shelf_id' => $data['shelf_id'],
            'location_id' => $data['location_id'],
        ]);
    }

    static public function getNewStorageManageInfo($storageManageId)
    {
        return StorageManageModel::select(
            'a.id',
            'type_id',
            'b.materiel_name',
            'b.type_name',
            'storage_id',
            'c.storage_name',
            'c.storage_address',
            'a.materiel_class_id',
            'd.class_name',
            'd.class_no',
            'b.cost',
            'a.in_storage_num',
            'a.virtual_storage_num',
            'location_id',
            'shelf_id'
        )
            ->from('storage_manage as a')
            ->leftJoin('materiel_type as b', 'b.id', '=', 'a.type_id')
            ->leftJoin('storage as c', 'c.id', '=', 'a.storage_id')
            ->leftJoin('materiel_class as d', 'd.id', '=', 'b.materiel_class_id')
            ->where([
                'a.id' => $storageManageId,
                'a.delete_flag' => 0
            ])->first();
    }


    //获取库存信息
    static public function getStorageManageInfo($storageManageId)
    {
        return StorageManageModel::select(
            'a.id',
            'type_id',
            'a.materiel_name',
            'a.type_name',
            'storage_id',
            'a.storage_name',
            'a.storage_address',
            'a.materiel_class_id',
            'd.class_name',
            'd.class_no',
            'a.materiel_mean_cost',
            'a.in_storage_num',
            'location_id',
            'shelf_id'
        )
            ->from('storage_manage as a')
            ->leftJoin('materiel_type as b', 'b.id', '=', 'a.type_id')
            ->leftJoin('storage as c', 'c.id', '=', 'a.storage_id')
            ->leftJoin('materiel_class as d', 'd.id', '=', 'b.materiel_class_id')
            ->where([
                'a.id' => $storageManageId,
                'a.delete_flag' => 0
            ])->first();
    }

    //生成新的库存信息
    static public function createNewStorageInfo($data, $materielTypeInfo, $storageInfo, $allocateNum)
    {
        return StorageManageModel::insertGetId([
            'materiel_class_id' => $materielTypeInfo['materiel_class_id'],
            'materiel_class_name' => $materielTypeInfo['class_name'],
            'materiel_class_no' => $materielTypeInfo['class_no'],
            'type_id' => $materielTypeInfo['id'],
            'materiel_name' => $materielTypeInfo['materiel_name'],
            'type_name' => $materielTypeInfo['type_name'],
            'materiel_no' => $materielTypeInfo['materiel_no'],
            'materiel_mean_cost' => $materielTypeInfo['cost'],
            'storage_id' => $storageInfo['id'],
            'storage_name' => $storageInfo['storage_name'],
            'storage_address' => $storageInfo['storage_address'],
            'in_storage_num' => $allocateNum,
            'virtual_storage_num' => $allocateNum,
            'main_id' => $data['main_id'],
            'materiel_original' => 1,
            'in_storage_time' => time(),
            'created_at' => time(),
            'shelf_id' => $data['shelf_id'],
            'location_id' => $data['location_id'],
        ]);
    }

    //create new batch no in storage
    static public function createdBatch($batchNo, $storageManageId, $materielTypeInfo, $data, $allocateNum)
    {
        return StorageBatchModel::insertGetId([
            'batch_no' => $batchNo,
            'storage_manage_id' => $storageManageId,
            'batch_num' => $allocateNum,
            'batch_left_num' => $allocateNum,
            'batch_cost' => $materielTypeInfo['cost'],
            'main_id' => $data['main_id'],
            'created_at' => time()
        ]);
    }

    //校验调入库存信息是否已存在
    static public function checkExist($data, $materielTypeInfo)
    {
        return StorageManageModel::where([
            'type_id' => $materielTypeInfo['id'],
            'storage_id' => $data['storage_id'],
        ])
            ->first();
    }

    static public function generatorBatchNo($data)
    {
        $batchNo = $data['batch_title'].date('YmdHis', time()).mt_rand(1000, 9999).'0';
        $checkBatchNo = StorageBatchModel::where('main_id', $data['main_id'])
            ->where('batch_no', $batchNo)->first();

        do {
            $batchNo = $data['batch_title'].date('YmdHis', time()).mt_rand(1000, 9999).'0';
        }
        while(!empty($checkBatchNo));

        return $batchNo;
    }
}
